using System;
using System.Data;
using System.Text;
using System.ComponentModel;
using CodeSmith.Engine;
using SchemaExplorer;

public class Common : CodeTemplate
{
    private string SpecialNames = "void";
    
	#region Name String Format
    
    public string ToPlural(String name)
    {
        String plural;
        if (name != null && name.Length > 0)
        {
            char ch = name[name.Length - 1];
            StringBuilder pluralBuilder = new StringBuilder(name);
            if (ch == 's' || ch == 'x')
            {
                pluralBuilder.Append("es");
            }
            else if (ch == 'y')
            {
                pluralBuilder.Remove(pluralBuilder.Length - 1, 1);
                pluralBuilder.Append("ies");
            }
            else
            {
                pluralBuilder.Append("s");
            }
            plural = pluralBuilder.ToString();
        }
        else
        {
            plural = name;
        }

        return plural;
    }
    public string ToSingular(string plural)
    {
        // convert to lowercase for easier comparison
        String lower = plural.ToLower();
        string res = string.Empty;

        // rule out a few exceptions
        if (lower == "feet")
        {
            res = "Foot";
        }
        else if (lower == "geese")
        {
            res = "Goose";
        }
        else if (lower == "men")
        {
            res = "Man";
        }
        else if (lower == "women")
        {
            res = "Woman";
        }
        else if (lower == "criteria")
        {
            res = "Criterion";
        }

        // plural uses "ies" if word ends with "y" preceeded by a non-vowel
        else if (lower.EndsWith("ies") && "aeiou".IndexOf(lower.Substring(lower.Length - 4, 1)) < 0)
        {
            res = plural.Substring(0, plural.Length - 3) + "y";
        }
        else if (lower.EndsWith("s"))
        {
            res = plural.Substring(0, plural.Length - 1); 
        }
        else
        {
            res = plural;
            //res = plural.Substring(0, plural.Length - 1);
        }

        // the result must preserve the original word//s capitalization
        if (plural == lower)
        {
            return res.ToLower();// it was an all-lowercase word
        }
        else if (plural == plural.ToUpper())
        {
            return res.ToUpper();   // it was an all-uppercase word
        }
        else
        {
            return res;    // return whatever is in "res"
        }
    }
	
    public string PascalCase(string source)
    {
        return source.Substring(0, 1).ToUpper() + source.Substring(1).Replace(" ", "");
    }
    
    public string CamelCase(string source)
    {
        return source.Substring(0, 1).ToLower() + source.Substring(1).Replace(" ", "");
    }
	
	public string NormalizeName(string value)
	{
        if(SpecialNames.IndexOf(value) >= 0)
			value = "@" + value;
        return value;
	}
	
	public string ClassName(string name)
	{
		return ToSingular(NormalizeName(name));
	}
	
	public string ControllerName(string name)
	{
		string cname = NormalizeName(name);
        int idx = cname.IndexOf("_");
        if(idx >= 0)
            cname = cname.Substring(idx+1);
        return ToSingular(cname);
	}
    
	public string PropertyName(string name)
	{
		return NormalizeName(name);
	}
	
	#endregion
	
	#region DbType Convertion
	
	public string DbType2SystemType(DbType dType, bool nullable)
	{
		string nullableStr = nullable ? "?" : "";
		switch(dType)
		{
			case DbType.AnsiString:
			case DbType.AnsiStringFixedLength:
				return "string";
			case DbType.Binary:
				return "byte[]";
			case DbType.Boolean:
				return "bool" + nullableStr;
			case DbType.Byte:
				return "byte";
			case DbType.Currency:
				return "decimal" + nullableStr;
			case DbType.Date:
				return "DateTime" + nullableStr;
			case DbType.DateTime:
				return "DateTime" + nullableStr;
			case DbType.Decimal:
				return "decimal" + nullableStr;
			case DbType.Double:
				return "double" + nullableStr;
			case DbType.Guid:
				return "Guid" + nullableStr;
			case DbType.Int16:
				return "short" + nullableStr;
			case DbType.Int32:
				return "int" + nullableStr;
			case DbType.Int64:
				return "long" + nullableStr;
			case DbType.Object:
				return "object";
			case DbType.SByte:
				return "sbyte" + nullableStr;
			case DbType.Single:
				return "float" + nullableStr;
			case DbType.String:
			case DbType.StringFixedLength:
				return "string";
			case DbType.Time:
				return "TimeSpan" + nullableStr;
			case DbType.UInt16:
				return "ushort" + nullableStr;
			case DbType.UInt32:
				return "uint" + nullableStr;
			case DbType.UInt64:
				return "ulong";
			case DbType.VarNumeric:
				return "decimal" + nullableStr;
			case DbType.Xml:
				return "System.Xml.Linq.XElement";
			default:
				return "__UNKNOWN__" + dType;
		}
	}
    
    public string GetSystemTypeDefaultValue(DbType dbType, bool nullable)
    {
		switch(dbType)
		{
			case DbType.AnsiString:
			case DbType.AnsiStringFixedLength:
				return "String.Empty";
			case DbType.Binary:
				return "null";
			case DbType.Boolean:
				return nullable ? "null" : "true";
			case DbType.Byte:
				return nullable ? "null" : "0";
			case DbType.Currency:
				return nullable ? "null" : "0";
			case DbType.Date:
			case DbType.DateTime:
				return nullable ? "null" : "DateTime.MinValue";
			case DbType.Decimal:
				return nullable ? "null" : "0";
			case DbType.Double:
				return nullable ? "null" : "0";
			case DbType.Guid:
				return nullable ? "null" : "new Guid()";
			case DbType.Int16:
				return nullable ? "null" : "0";
			case DbType.Int32:
				return nullable ? "null" : "0";
			case DbType.Int64:
				return nullable ? "null" : "0";
			case DbType.Object:
				return "null";
			case DbType.SByte:
				return nullable ? "null" : "0";
			case DbType.Single:
				return nullable ? "null" : "0";
			case DbType.String:
			case DbType.StringFixedLength:
				return "String.Empty";
			case DbType.Time:
				return nullable ? "null" : "DateTime.MinValue";
			case DbType.UInt16:
				return nullable ? "null" : "0";
			case DbType.UInt32:
				return nullable ? "null" : "0";
			case DbType.UInt64:
				return nullable ? "null" : "0";
			case DbType.VarNumeric:
				return "null";
			case DbType.Xml:
				return "null";
			default:
				return "null";
		}
    }
    
    public string GetTryParse(string colName, string outName, DbType dbType)
    {
		switch(dbType)
		{	
			case DbType.String:
			case DbType.StringFixedLength:
			case DbType.AnsiString:
			case DbType.AnsiStringFixedLength:
				return outName + " = " + colName+".ToString()";
			case DbType.Date:
			case DbType.DateTime:
				return "DateTime.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Boolean:
				return "bool.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Currency:
				return "decimal.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Decimal:
				return "decimal.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Double:
				return "double.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Int16:
				return "int.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Int32:
				return "int.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Int64:
				return "int.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.SByte:
				return "sbyte.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Single:
				return "int.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.UInt16:
				return "uint.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.UInt32:
				return "uint.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.UInt64:
				return "uint.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.VarNumeric:
				return "decimal.TryParse(" + colName + ".ToString(), out " + outName + ");";
			case DbType.Guid:
				return "Guid.TryParse(" + colName + ".ToString(), out " + outName + ");";
			default:
				return "";
		}
    }
	
	public string GetConvert(string colName,DbType dbType)
	{
		switch(dbType)
		{	
			case DbType.String:
			case DbType.StringFixedLength:
			case DbType.AnsiString:
			case DbType.AnsiStringFixedLength:
				return colName+".ToString()";
			case DbType.Date:
			case DbType.DateTime:
				return "Convert.ToDateTime("+colName+")";
			case DbType.Boolean:
				return "Convert.ToBoolean("+colName+")";
			case DbType.Currency:
				return "Convert.ToDecimal("+colName+")";
			case DbType.Decimal:
				return "Convert.ToDecimal("+colName+")";
			case DbType.Double:
				return "Convert.ToDouble("+colName+")";
			case DbType.Int16:
				return "Convert.ToInt16("+colName+")";
			case DbType.Int32:
				return "Convert.ToInt32("+colName+")";
			case DbType.Int64:
				return "Convert.ToInt64("+colName+")";
			case DbType.SByte:
				return "Convert.ToByte("+colName+")";
			case DbType.Single:
				return "Convert.ToSingle("+colName+")";
			case DbType.UInt16:
				return "Convert.ToUInt16("+colName+")";
			case DbType.UInt32:
				return "Convert.ToUInt32("+colName+")";
			case DbType.UInt64:
				return "Convert.ToUInt64("+colName+")";
			case DbType.VarNumeric:
				return "Convert.ToDecimal("+colName+")";
			case DbType.Guid:
				return "Convert.ToGuid("+colName+")";
			default:
				return "Convert.ToString("+colName+")";
		}
	}

	#endregion
    	
	public string FormatColumns(ColumnSchemaCollection columns, Func<ColumnSchema, string> formater, string spliter)
	{
		string str = "";

		for(int i=0; i < columns.Count; i++)
		{
			ColumnSchema col = columns[i];
			
			str += formater(col);
			if(i < columns.Count - 1)
				str += spliter;
		}
		return str;
	}		
}